package usi.ch.onto.lucene.indexing;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.tika.parser.ParsingReader;

import usi.ch.onto.common.FileUtils;
import usi.ch.onto.lucene.analysis.PlingStemAnalyzer;

/**
 * 
 * 
 * 
 * @author Aida This is the class that does document indexing and creates Lucene
 *         Indexes It uses the PlingStemmer with the custom English list of
 *         stopwords
 * 
 */

public class Indexer {
	private String indexname;
	private IndexWriter iWriter;
	private String directoryToIndex;

	public Indexer(String indexname, String directorytoindex)
			throws Exception {
		this.indexname = indexname;
		this.directoryToIndex = directorytoindex;
		validateDirectory(directoryToIndex);

		Directory directory = FSDirectory.open(new File(this.indexname));
		Analyzer analyzer = new PlingStemAnalyzer(false);
		// StandardAnalyzer analyzer = new StandardAnalyzer(Version.LUCENE_30);
		iWriter = new IndexWriter(directory, analyzer, true,
				IndexWriter.MaxFieldLength.UNLIMITED);
	}

	private void validateDirectory(String path) throws Exception {
		File docDir = new File(path);

		if (!docDir.exists() || !docDir.canRead())
			throw new Exception("Can not read the directory:   "
					+ docDir.getPath() + " check if it exists");

	}

	/**
	 * Method that creates the index
	 * 
	 * @param: indexname - name of the index file that will be created
	 * @param: directorytoindex - name of directory with files for indexing
	 * 
	 * */

	public void makeIndex() throws Exception {

		final File docDir = new File(directoryToIndex);

		long start = System.currentTimeMillis();
		try {
			System.out.println("Indexing to directory:   " + indexname);
			indexDir(docDir);
			iWriter.optimize();
			iWriter.commit();
			System.out.println("Time to index was "
					+ ((System.currentTimeMillis() - start) / 1000.0)
					+ " miliseconds");

		} catch (CorruptIndexException e) {
			System.out.println("Error in indexing files."
					+ e.getLocalizedMessage());
		} catch (IOException e) {
			System.out.println("Error in indexing files."
					+ e.getLocalizedMessage());
		}
	}

	/**
	 * Recursive function for the cases there is several levels of directories
	 * 
	 * @param: writer - object to write the index
	 * @param: fileIn - file or directory that needs to be indexed
	 * */
	private long indexDir(File fileIn) throws IOException {
		long filesProcessed = 0;
		if (fileIn.canRead()) {
			if (fileIn.isDirectory()) {
				File[] fileList = fileIn.listFiles();
				for (File f : fileList) {
					if (f.isDirectory())
						indexDir(f);
					if (isUnsupportedFormat(f) == false) {
						System.out.println("Indexing file: " + f.getName());
						if (index(f))
							filesProcessed++;
					}
				}
			}
		}
		return filesProcessed;
	}

	// private boolean isFormatSupported(File f) {
	// String[] extensions = new String[] { ".rtf", ".txt", ".html", ".xml",
	// ".pdf", ".doc", ".docx", ".xls", ".xlsx", ".odt", ".ods",
	// ".ppt", ".pptx" };
	//
	// for (int i = 0; i < extensions.length; i++) {
	// if (f.getName().endsWith(extensions[i]))
	// return true;
	// }
	// return false;
	// }

	private boolean isUnsupportedFormat(File f) {
		String[] extensions = new String[] { ".js", ".css", ".jpg" };

		for (int i = 0; i < extensions.length; i++) {
			if (f.getName().endsWith(extensions[i]))
				return true;
		}
		return false;
	}

	private boolean index(File f) {
		String uuid;
		String docFilename;
		String docDateModified;
		String docText;
		Document doc;
		try {
			uuid = FileUtils.getDocUuid(f);
			docFilename = f.getName();
			docDateModified = String.valueOf(f.lastModified());

			docText = getDocumentText(f);
		} catch (Exception e) {
			System.out.println("Error in indexing file."
					+ e.getLocalizedMessage());
			return false;
		}

		doc = new Document();
		doc.add(new Field("uuid", uuid, Field.Store.YES,
				Field.Index.NO));
		// NOT_ANALYZED
		doc.add(new Field("filename", docFilename, Field.Store.YES,
				Field.Index.ANALYZED));
		doc.add(new Field("lastModified", docDateModified, Field.Store.YES,
				Field.Index.NO));
		doc
				.add(new Field("text", docText, Field.Store.NO,
						Field.Index.ANALYZED));

		try {
			iWriter.addDocument(doc);
			return true;
		} catch (CorruptIndexException e) {
			System.out.println("Error in indexing file."
					+ e.getLocalizedMessage());
			return false;
		} catch (IOException e) {
			System.out.println("Error in indexing file."
					+ e.getLocalizedMessage());
			return false;
		}
	}

	private String getDocumentText(File f)
			throws IOException {
		InputStream stream = new FileInputStream(f);
		ParsingReader reader = new ParsingReader(stream);

		StringBuffer buffer = new StringBuffer();
		try {
			BufferedReader r = new BufferedReader(reader);
			String line = null;
			do {
				line = r.readLine();
				buffer.append(line + " "); // a space is added otherwise final
				// words are not correctly indexed
			} while (line != null);
		} finally {
			reader.close();
		}
		return buffer.toString();
	}
}